/*
 *
 *   Copyright (C) 2005 by Raymond Huang
 *   plushuang at users.sourceforge.net
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  ---
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU Lesser General Public License in all respects
 *  for all of the code used other than OpenSSL.  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so.  If you
 *  do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 *
 */

#include "proxy_editor.h"
#include "proxy_list_view.h"
#include "node_list_model.h"
#include <urlglib/ug_i18n.h>

// Signal handler ----------------------------------------------------

static void on_proxy_disable (GtkToggleButton* button, ProxyEditor* view)
{
	proxy_editor_decide_sensitive (view);
}

static void on_proxy_selection (GtkTreeSelection* selection, ProxyEditor* view)
{
	if (view->deleting)
		return;
	view->selection_changed++;    // for on_proxy_info_changed ()
	proxy_editor_decide_sensitive (view);
	view->selection_changed--;    // for on_proxy_info_changed ()
}

static void on_proxy_cursor_changed (GtkTreeView* treeview, ProxyEditor* view)
{
	GtkTreeModel* model;
	GtkTreePath*  path;
	GtkTreeIter   iter;
	ProxyNode*    pnode;

	if (view->deleting || view->moving)
		return;
	view->selection_changed++;    // for on_proxy_info_changed ()
	gtk_tree_view_get_cursor (treeview, &path, NULL);
	model = gtk_tree_view_get_model (treeview);
	if (model) {
		gtk_tree_model_get_iter (model, &iter, path);
		gtk_tree_path_free (path);
		gtk_tree_model_get (model, &iter, 0, &pnode, -1);
		proxy_info_view_set (&view->proxy_info_view, pnode);
	}
	view->selection_changed--;    // for on_proxy_info_changed ()
}

static void on_proxy_info_changed (GtkWidget* widget, ProxyEditor* view)
{
	if (view->selection_changed)
		return;
	gtk_widget_set_sensitive (view->button_proxy_update, TRUE);
}

static void on_proxy_new (GtkWidget* widget, ProxyEditor* dview)
{
	GtkAdjustment*  adjustment;
	GtkTreePath*    path;
	ProxyNode*      pnode;
	gdouble         value;

	pnode = proxy_node_new ();
	download_node_prepend_proxy (dview->dnode, pnode);

	// change cursor
	path = gtk_tree_path_new ();
	gtk_tree_path_prepend_index (path, 0);
	gtk_tree_view_set_cursor (dview->proxy_list_view, path, NULL, FALSE);
	gtk_tree_path_free (path);

	// scrolled to first
	adjustment = gtk_scrolled_window_get_vadjustment (dview->proxy_scrolled);
	g_object_get (adjustment, "lower", &value, NULL);
	gtk_adjustment_set_value (adjustment, value);
	gtk_adjustment_value_changed (adjustment);
}

static void on_proxy_delete (GtkWidget* widget, ProxyEditor* view)
{
	GtkTreePath*  path;
	ProxyNode*    pnode;
	int  index;

	gtk_tree_view_get_cursor (view->proxy_list_view, &path, NULL);
	if (path) {
		index = *gtk_tree_path_get_indices (path);
		pnode = download_node_nth_proxy (view->dnode, index);

		if (proxy_node_next (pnode)) {
			gtk_tree_path_next (path);
		} else {
			if (index)
				gtk_tree_path_prev (path);
			else {
				gtk_tree_path_free (path);
				path = NULL;
			}
		}

		if (path) {
			gtk_tree_view_set_cursor (view->proxy_list_view, path, NULL, FALSE);
			gtk_tree_path_free (path);
			view->deleting = TRUE;    // for on_proxy_selection () and on_proxy_cursor_changed ()
		}
		proxy_node_unlink (pnode);
		proxy_node_unref (pnode);
		view->deleting = FALSE;    // for on_proxy_selection () and on_proxy_cursor_changed ()
	}
}

static void on_proxy_update (GtkWidget* widget, ProxyEditor* view)
{
	GtkTreeModel* model;
	GtkTreePath*  path;
	GtkTreeIter   iter;
	ProxyNode*    pnode;
	int  index;

	gtk_tree_view_get_cursor (view->proxy_list_view, &path, NULL);
	if (path) {
		index = *gtk_tree_path_get_indices (path);

		pnode = download_node_nth_proxy (view->dnode, index);
		proxy_info_view_get (&view->proxy_info_view, pnode);

		model = gtk_tree_view_get_model (view->proxy_list_view);
		gtk_tree_model_get_iter (model, &iter, path);
		gtk_tree_model_row_changed (model, path, &iter);
		gtk_tree_path_free (path);

		gtk_widget_set_sensitive (view->button_proxy_update, FALSE);
	}
}

static void on_proxy_move_top (GtkWidget* widget, ProxyEditor* view)
{
	GtkTreePath*  path;
	ProxyNode*    pnode;
	int  index;

	gtk_tree_view_get_cursor (view->proxy_list_view, &path, NULL);
	if (path) {
		index = *gtk_tree_path_get_indices (path);
		gtk_tree_path_free (path);
		if (index) {
			view->moving = TRUE;
			pnode = download_node_nth_proxy (view->dnode, index);
			view->deleting = TRUE;
			proxy_node_unlink (pnode);
			view->deleting = FALSE;
			download_node_prepend_proxy (view->dnode, pnode);
			path = gtk_tree_path_new ();
			gtk_tree_path_prepend_index (path, 0);
			gtk_tree_view_set_cursor (view->proxy_list_view, path, NULL, FALSE);
			gtk_tree_path_free (path);
			view->moving = FALSE;
		}
	}
}

static void on_proxy_move_bottom (GtkWidget* widget, ProxyEditor* view)
{
	GtkTreePath*  path;
	ProxyNode*    pnode;
	int  index;

	gtk_tree_view_get_cursor (view->proxy_list_view, &path, NULL);
	if (path) {
		index = *gtk_tree_path_get_indices (path);
		gtk_tree_path_free (path);

		view->moving = TRUE;
		pnode = download_node_nth_proxy (view->dnode, index);
		view->deleting = TRUE;
		proxy_node_unlink (pnode);
		view->deleting = FALSE;
		download_node_append_proxy (view->dnode, pnode);
		index = download_node_n_proxy (view->dnode) - 1;
		if (index > 0) {
			path = gtk_tree_path_new ();
			gtk_tree_path_prepend_index (path, index);
			gtk_tree_view_set_cursor (view->proxy_list_view, path, NULL, FALSE);
			gtk_tree_path_free (path);
		}
		view->moving = FALSE;
	}
}

static void on_proxy_move_up (GtkWidget* widget, ProxyEditor* view)
{
	GtkTreePath*  path;
	ProxyNode*    pnode;
	ProxyNode*    pnode_prev;
	int  index;

	gtk_tree_view_get_cursor (view->proxy_list_view, &path, NULL);
	if (path) {
		index = *gtk_tree_path_get_indices (path);
		gtk_tree_path_free (path);
		pnode = download_node_nth_proxy (view->dnode, index);
		pnode_prev = proxy_node_prev (pnode);
		if (pnode_prev) {
			view->moving = TRUE;
			view->deleting = TRUE;
			proxy_node_unlink (pnode);
			view->deleting = FALSE;
			download_node_insert_before (view->dnode, pnode_prev, pnode);
			path = gtk_tree_path_new ();
			gtk_tree_path_prepend_index (path, index-1);
			gtk_tree_view_set_cursor (view->proxy_list_view, path, NULL, FALSE);
			gtk_tree_path_free (path);
			view->moving = FALSE;
		}
	}
}

static void on_proxy_move_down (GtkWidget* widget, ProxyEditor* view)
{
	GtkTreePath*  path;
	ProxyNode*    pnode;
	ProxyNode*    pnode_next;
	int  index;

	gtk_tree_view_get_cursor (view->proxy_list_view, &path, NULL);
	if (path) {
		index = *gtk_tree_path_get_indices (path);
		gtk_tree_path_free (path);
		pnode = download_node_nth_proxy (view->dnode, index);
		pnode_next = proxy_node_next (pnode);
		if (pnode_next) {
			view->moving = TRUE;
			view->deleting = TRUE;
			proxy_node_unlink (pnode);
			view->deleting = FALSE;
			download_node_insert_after (view->dnode, pnode_next, pnode);
			path = gtk_tree_path_new ();
			gtk_tree_path_prepend_index (path, index+1);
			gtk_tree_view_set_cursor (view->proxy_list_view, path, NULL, FALSE);
			gtk_tree_path_free (path);
			view->moving = FALSE;
		}
	}
}

void proxy_editor_on_destroy (GtkWidget* widget, ProxyEditor* peditor)
{
	download_node_unref (peditor->dnode);
}

// ProxyEditor -------------------------------------------------------

void proxy_editor_init (ProxyEditor* view)
{
	GtkWidget* top_table;
	GtkEditable* editable;
	GtkTreeSelection* selection;

	view->dnode  = download_node_new ();
	view->moving = FALSE;
	view->deleting = FALSE;
	view->selection_changed = 0;
	view->top_widget = gtk_table_new (9, 4, FALSE);
	top_table = view->top_widget;
	gtk_container_set_border_width (GTK_CONTAINER (top_table), 2);
	proxy_info_view_init (&view->proxy_info_view);
	gtk_table_attach (GTK_TABLE (top_table), view->proxy_info_view.top_widget, 0, 7, 8, 9,
	                  GTK_FILL | GTK_EXPAND, GTK_SHRINK, 1, 2);

/*
	view->combo_proxy_mode = gtk_combo_box_new_text ();
	gtk_combo_box_append_text (GTK_COMBO_BOX (view->combo_proxy_mode),
	                           _("Direct connect"));
	gtk_combo_box_append_text (GTK_COMBO_BOX (view->combo_proxy_mode),
	                           _("Use first proxy only"));
	gtk_combo_box_append_text (GTK_COMBO_BOX (view->combo_proxy_mode),
	                           _("Try all proxy from top to bottom if download fail"));
	gtk_table_attach (GTK_TABLE (top_table), view->combo_proxy_mode, 0, 4, 0, 1,
	                  GTK_FILL | GTK_EXPAND, GTK_SHRINK, 1, 2);
*/

	view->radio_direct = gtk_radio_button_new_with_mnemonic (NULL,
	                                                         _("Direct connect"));
	view->radio_first = gtk_radio_button_new_with_mnemonic_from_widget (
	                             (GtkRadioButton*)view->radio_direct,
	                             _("Use first proxy only"));
	view->radio_try_all = gtk_radio_button_new_with_mnemonic_from_widget (
	                             (GtkRadioButton*)view->radio_direct,
	                             _("Try all from top to bottom until download succeeds"));
	gtk_table_attach (GTK_TABLE (top_table), view->radio_direct, 0, 4, 0, 1,
	                  GTK_FILL | GTK_EXPAND, GTK_SHRINK, 1, 0);
	gtk_table_attach (GTK_TABLE (top_table), view->radio_first, 0, 4, 1, 2,
	                  GTK_FILL | GTK_EXPAND, GTK_SHRINK, 1, 0);
	gtk_table_attach (GTK_TABLE (top_table), view->radio_try_all, 0, 4, 2, 3,
	                  GTK_FILL | GTK_EXPAND, GTK_SHRINK, 1, 0);

	// list view
	view->proxy_scrolled = (GtkScrolledWindow*)gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_shadow_type (view->proxy_scrolled, GTK_SHADOW_IN);
	gtk_scrolled_window_set_policy (view->proxy_scrolled,
	                                GTK_POLICY_AUTOMATIC,
	                                GTK_POLICY_AUTOMATIC);
	gtk_table_attach (GTK_TABLE (top_table), GTK_WIDGET (view->proxy_scrolled), 0, 3, 3, 7,
	                  GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 1, 2);
	view->proxy_list_view = proxy_list_view_new ();
	view->proxy_model = (GtkTreeModel*)node_list_model_new (BASE_NODE (view->dnode));
	gtk_tree_view_set_model (view->proxy_list_view, view->proxy_model);
	g_object_unref (view->proxy_model);
	gtk_container_add (GTK_CONTAINER(view->proxy_scrolled),
	                   GTK_WIDGET (view->proxy_list_view));

	// buttons
	view->button_proxy_move_top = gtk_button_new ();
	gtk_container_add (GTK_CONTAINER (view->button_proxy_move_top),
	    gtk_image_new_from_stock (GTK_STOCK_GOTO_TOP, GTK_ICON_SIZE_LARGE_TOOLBAR));
	gtk_table_attach (GTK_TABLE (top_table), view->button_proxy_move_top, 3, 4, 3, 4,
	                  GTK_SHRINK, GTK_SHRINK, 2, 2);

	view->button_proxy_move_up = gtk_button_new ();
	gtk_container_add (GTK_CONTAINER (view->button_proxy_move_up),
	    gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_LARGE_TOOLBAR));
	gtk_table_attach (GTK_TABLE (top_table), view->button_proxy_move_up, 3, 4, 4, 5,
	                  GTK_SHRINK, GTK_SHRINK, 2, 2);

	view->button_proxy_move_down = gtk_button_new ();
	gtk_container_add (GTK_CONTAINER (view->button_proxy_move_down),
	    gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_LARGE_TOOLBAR));
	gtk_table_attach (GTK_TABLE (top_table), view->button_proxy_move_down, 3, 4, 5, 6,
	                  GTK_SHRINK, GTK_SHRINK, 2, 2);

	view->button_proxy_move_bottom = gtk_button_new ();
	gtk_container_add (GTK_CONTAINER (view->button_proxy_move_bottom),
	    gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, GTK_ICON_SIZE_LARGE_TOOLBAR));
	gtk_table_attach (GTK_TABLE (top_table), view->button_proxy_move_bottom, 3, 4, 6, 7,
	                  GTK_SHRINK, GTK_SHRINK, 2, 2);

	view->button_proxy_new = gtk_button_new_from_stock (GTK_STOCK_NEW);
	view->button_proxy_delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
	view->button_proxy_update = gtk_button_new_from_stock (GTK_STOCK_APPLY);
	gtk_table_attach (GTK_TABLE (top_table), view->button_proxy_new, 0, 1, 7, 8,
	                  GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 1, 2);
	gtk_table_attach (GTK_TABLE (top_table), view->button_proxy_delete, 1, 2, 7, 8,
	                  GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 1, 2);
	gtk_table_attach (GTK_TABLE (top_table), view->button_proxy_update, 2, 3, 7, 8,
	                  GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 1, 2);

	// Proxy page signal
	editable = GTK_EDITABLE (view->proxy_info_view.entry_host);
	g_signal_connect (editable, "changed", G_CALLBACK (on_proxy_info_changed), view);
	editable = GTK_EDITABLE (view->proxy_info_view.spin_port);
	g_signal_connect (editable, "changed", G_CALLBACK (on_proxy_info_changed), view);
	editable = GTK_EDITABLE (view->proxy_info_view.entry_username);
	g_signal_connect (editable, "changed", G_CALLBACK (on_proxy_info_changed), view);
	editable = GTK_EDITABLE (view->proxy_info_view.entry_password);
	g_signal_connect (editable, "changed", G_CALLBACK (on_proxy_info_changed), view);
	g_signal_connect (view->proxy_info_view.combo_type, "changed",
	                  G_CALLBACK (on_proxy_info_changed), view);
	g_signal_connect (view->proxy_info_view.toggle_authentication, "toggled",
	                  G_CALLBACK (on_proxy_info_changed), view);

	selection = gtk_tree_view_get_selection (view->proxy_list_view);
	g_signal_connect (selection, "changed",
	                  G_CALLBACK(on_proxy_selection), view);
	g_signal_connect (view->proxy_list_view, "cursor-changed",
	                  G_CALLBACK(on_proxy_cursor_changed), view);
	g_signal_connect (view->radio_direct, "toggled",
	                  G_CALLBACK(on_proxy_disable), view);
	g_signal_connect (view->button_proxy_new, "clicked",
	                  G_CALLBACK(on_proxy_new), view);
	g_signal_connect (view->button_proxy_delete, "clicked",
	                  G_CALLBACK(on_proxy_delete), view);
	g_signal_connect (view->button_proxy_update, "clicked",
	                  G_CALLBACK(on_proxy_update), view);
	g_signal_connect (view->button_proxy_move_top, "clicked",
	                  G_CALLBACK(on_proxy_move_top), view);
	g_signal_connect (view->button_proxy_move_bottom, "clicked",
	                  G_CALLBACK(on_proxy_move_bottom), view);
	g_signal_connect (view->button_proxy_move_up, "clicked",
	                  G_CALLBACK(on_proxy_move_up), view);
	g_signal_connect (view->button_proxy_move_down, "clicked",
	                  G_CALLBACK(on_proxy_move_down), view);

	g_signal_connect (view->top_widget, "destroy",
	                  G_CALLBACK(proxy_editor_on_destroy), view);
	on_proxy_disable (GTK_TOGGLE_BUTTON (view->radio_direct), view);

	gtk_widget_show_all (top_table);
}

void proxy_editor_decide_sensitive (ProxyEditor* view)
{
	GtkTreeSelection* selection;
	gboolean proxy_selected;
	gboolean proxy_enable;

	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (view->radio_direct))) {
		proxy_selected = FALSE;
		proxy_enable   = FALSE;
	} else {
		selection = gtk_tree_view_get_selection (view->proxy_list_view);
		proxy_selected = gtk_tree_selection_get_selected (selection, NULL, NULL);
		proxy_enable   = TRUE;
	}

	gtk_widget_set_sensitive (GTK_WIDGET (view->proxy_list_view), proxy_enable);
	gtk_widget_set_sensitive (view->button_proxy_new, proxy_enable);

	gtk_widget_set_sensitive (view->proxy_info_view.top_widget, proxy_selected);
	gtk_widget_set_sensitive (view->button_proxy_move_up, proxy_selected);
	gtk_widget_set_sensitive (view->button_proxy_move_down, proxy_selected);
	gtk_widget_set_sensitive (view->button_proxy_move_top, proxy_selected);
	gtk_widget_set_sensitive (view->button_proxy_move_bottom, proxy_selected);
	gtk_widget_set_sensitive (view->button_proxy_delete, proxy_selected);
	if (view->moving == FALSE)
		gtk_widget_set_sensitive (view->button_proxy_update, FALSE);
}

void proxy_editor_set (ProxyEditor* view, DownloadNode* dnode)
{
	switch (dnode->proxy_mode) {
	case DOWNLOAD_PROXY_NONE:
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(view->radio_direct), TRUE);
		break;
	case DOWNLOAD_PROXY_FIRST:
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(view->radio_first), TRUE);
		break;
	case DOWNLOAD_PROXY_TRY_ALL:
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(view->radio_try_all), TRUE);
		break;
	}

	download_node_assign_proxy (view->dnode, dnode);
}

void proxy_editor_get (ProxyEditor* view, DownloadNode* dnode)
{
	if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(view->radio_direct)) )
		dnode->proxy_mode = DOWNLOAD_PROXY_NONE;
	else if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(view->radio_first)) )
		dnode->proxy_mode = DOWNLOAD_PROXY_FIRST;
	else
		dnode->proxy_mode = DOWNLOAD_PROXY_TRY_ALL;

	download_node_assign_proxy (dnode, view->dnode);
}

